package com.gungnir.trial.mapper.threerate;

import com.gungnir.trial.entity.ThreeRate;
import com.gungnir.trial.mapper.LogicalMapper;
import com.tyrfing.common.TyrfingErrorCode;
import com.tyrfing.exceptions.TyrfingServiceException;
import com.tyrfing.model.Pagination;
import com.tyrfing.mongo.TyrfingMongoDb;
import com.tyrfing.mongo.exception.TyrfingMongoException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * Mapper for handling ThreeRate entities.
 * Provides CRUD operations and various query methods.
 */
@Component
public class ThreeRateMapper extends LogicalMapper<ThreeRate> {
    protected final Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private MongoTemplate mongoTemplate;
    protected ThreeRateMapper(TyrfingMongoDb tyrfingMongoDb) {
        super(tyrfingMongoDb);
    }

    // 插入ThreeRate记录，处理主键冲突
    public void insertThreeRate(ThreeRate threeRate) {
        try {
            this.getTemplate().insert(threeRate);
        } catch (TyrfingMongoException e) {
            log.error("Failed to insert ThreeRate record, classroom code: {}, image shot time: {}",
                    threeRate.getClassRoomCode(), threeRate.getImagShotTime(), e);
        }
    }

    //传入总人数(shouldAttendance),抬头人数(attendanceFaceCount),到达人数(attendanceCount)，前排人数(frontAttendancetCount)，前排数量(clroFrontSeatCount)，教室编码(classRoomCode)，教学班次(teachingClassCode)，考勤分析时间(imagShotTime)，计算后插入ThreeRate记录
    public void countAndInsertThreeRate(int shouldAttendance, int attendanceFaceCount, int attendanceCount, int frontAttendancetCount, int clroFrontSeatCount, String classRoomCode, String teachingClassCode, Long imagShotTime) {
        // 前排率
        double frontRowRate = (double) frontAttendancetCount / clroFrontSeatCount * 100;
        frontRowRate = Double.parseDouble(String.format("%.2f", frontRowRate));

        // 抬头率
        double headUpRate = (double) attendanceFaceCount / attendanceCount * 100;
        headUpRate = Double.parseDouble(String.format("%.2f", headUpRate));

        // 到课率
        double attendanceRate = (double) attendanceCount / shouldAttendance * 100;
        attendanceRate = Double.parseDouble(String.format("%.2f", attendanceRate));
        ThreeRate record=new ThreeRate();
        record.setAttendanceRate(attendanceRate);
        record.setFrontRowRate(frontRowRate);
        record.setHeadUpRate(headUpRate);
        record.setClassRoomCode(classRoomCode);
        record.setTeachingClassCode(teachingClassCode);
        record.setImagShotTime(imagShotTime);
        this.insertThreeRate(record);
    }

    // 删除ThreeRate记录通过其复合主键(imagShotTime, classRoomCode)
    public void deleteByPrimaryKey(Long imagShotTime, String classRoomCode) {
        Criteria criteria = Criteria.where("imagShotTime").is(imagShotTime)
                .and("classRoomCode").is(classRoomCode);
        try {
            getTemplate().remove(new Query(criteria), getClazz());
        } catch (TyrfingMongoException e) {
            log.error("Failed to delete ThreeRate record, classroom code: {}, image shot time: {}",
                    classRoomCode, imagShotTime, e);
        }
    }

    // 更新ThreeRate记录通过其复合主键(imagShotTime, classRoomCode)
    public void updateThreeRate(ThreeRate threeRate) {
        Criteria criteria = Criteria.where("imagShotTime").is(threeRate.getImagShotTime())
                .and("classRoomCode").is(threeRate.getClassRoomCode());
        try {
            this.getTemplate().findAndReplace(new Query(criteria), threeRate);
        } catch (TyrfingMongoException e) {
            log.error("Failed to update ThreeRate record, classroom code: {}, image shot time: {}",
                    threeRate.getClassRoomCode(), threeRate.getImagShotTime(), e);
        }
    }

    //根据时间范围查询ThreeRate记录

//    public List<ThreeRate> findByTimeRange(Long startTime, Long endTime) {
//        Criteria criteria = Criteria.where("imagShotTime").gte(startTime).lte(endTime);
//        return this.list(new Query(criteria));
//    }
public Pagination<ThreeRate> findByTimeRangePaged(Integer pageSize, Integer pageNum, Long startTime, Long endTime) throws Exception {
    if (pageSize == null) {
        throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少每页数量.");
    }
    if (pageNum == null) {
        throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少当前页号.");
    }
    if (startTime == null) {
        throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少开始时间.");
    }
    if (endTime == null) {
        throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少结束时间.");
    }

    // 构造查询条件
    Query query = new Query();
    query.addCriteria(Criteria.where("imagShotTime").gte(startTime).lte(endTime));

    // 设置分页
    Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
    query.with(pageable);

    // 查询 MongoDB
    List<ThreeRate> threeRates = mongoTemplate.find(query, ThreeRate.class);
    // 查询总记录数
    long totalCount = mongoTemplate.count(query.skip(-1).limit(-1), ThreeRate.class);

    // 创建分页对象并设置数据
    Pagination<ThreeRate> pagination = new Pagination<>(pageSize, pageNum);
    pagination.setData(threeRates);
    pagination.setTotal((int) totalCount);

    return pagination;
}

    // 根据classRoomCode查询ThreeRate记录数组
//    public List<ThreeRate> findByClassRoomCode(String classRoomCode) {
//        Criteria criteria = Criteria.where("classRoomCode").is(classRoomCode);
//        return this.list(new Query(criteria));
//    }

    public Pagination<ThreeRate> findByClassRoomCodePaged(Integer pageSize, Integer pageNum, String classRoomCode) throws Exception {
        if (pageSize == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少每页数量.");
        }
        if (pageNum == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少当前页号.");
        }
        if (classRoomCode == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少教室代码.");
        }

        // 构造查询条件
        Query query = new Query();
        query.addCriteria(Criteria.where("classRoomCode").is(classRoomCode));

        // 设置分页
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
        query.with(pageable);

        // 查询 MongoDB
        List<ThreeRate> threeRates = mongoTemplate.find(query, ThreeRate.class);
        // 查询总记录数
        long totalCount = mongoTemplate.count(query.skip(-1).limit(-1), ThreeRate.class);

        // 创建分页对象并设置数据
        Pagination<ThreeRate> pagination = new Pagination<>(pageSize, pageNum);
        pagination.setData(threeRates);
        pagination.setTotal((int) totalCount);

        return pagination;
    }


    // 根据teachingClassCode查询ThreeRate记录数组
//    public List<ThreeRate> findByTeachingClassCode(String teachingClassCode) {
//        Criteria criteria = Criteria.where("teachingClassCode").is(teachingClassCode);
//        return this.list(new Query(criteria));
//    }

    public Pagination<ThreeRate> findByTeachingClassCodePaged(Integer pageSize, Integer pageNum, String teachingClassCode) throws Exception {
        if (pageSize == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少每页数量.");
        }
        if (pageNum == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少当前页号.");
        }
        if (teachingClassCode == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少教学班代码.");
        }

        // 构造查询条件
        Query query = new Query();
        query.addCriteria(Criteria.where("teachingClassCode").is(teachingClassCode));

        // 设置分页
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
        query.with(pageable);

        // 查询 MongoDB
        List<ThreeRate> threeRates = mongoTemplate.find(query, ThreeRate.class);
        // 查询总记录数
        long totalCount = mongoTemplate.count(query.skip(-1).limit(-1), ThreeRate.class);

        // 创建分页对象并设置数据
        Pagination<ThreeRate> pagination = new Pagination<>(pageSize, pageNum);
        pagination.setData(threeRates);
        pagination.setTotal((int) totalCount);

        return pagination;
    }


    // 根据时间范围和classRoomCode查询ThreeRate记录数组
//    public List<ThreeRate> findByTimeRangeAndClassRoomCode(Long startTime, Long endTime, String classRoomCode) {
//        Criteria criteria = Criteria.where("imagShotTime").gte(startTime).lte(endTime)
//                .and("classRoomCode").is(classRoomCode);
//        return this.list(new Query(criteria));
//    }

    public Pagination<ThreeRate> findByTimeRangeAndClassRoomCodePaged(Integer pageSize, Integer pageNum, Long startTime, Long endTime, String classRoomCode) throws Exception {
        if (pageSize == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少每页数量.");
        }
        if (pageNum == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少当前页号.");
        }
        if (startTime == null || endTime == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少时间范围.");
        }
        if (classRoomCode == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少教室代码.");
        }

        // 构造查询条件
        Query query = new Query();
        query.addCriteria(Criteria.where("imagShotTime").gte(startTime).lte(endTime)
                .and("classRoomCode").is(classRoomCode));

        // 设置分页
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
        query.with(pageable);

        // 查询 MongoDB
        List<ThreeRate> threeRates = mongoTemplate.find(query, ThreeRate.class);
        // 查询总记录数
        long totalCount = mongoTemplate.count(query.skip(-1).limit(-1), ThreeRate.class);

        // 创建分页对象并设置数据
        Pagination<ThreeRate> pagination = new Pagination<>(pageSize, pageNum);
        pagination.setData(threeRates);
        pagination.setTotal((int) totalCount);

        return pagination;
    }


    // 根据时间范围和teachingClassCode查询ThreeRate记录数组
//    public List<ThreeRate> findByTimeRangeAndTeachingClassCode(Long startTime, Long endTime, String teachingClassCode) {
//        Criteria criteria = Criteria.where("imagShotTime").gte(startTime).lte(endTime)
//                .and("teachingClassCode").is(teachingClassCode);
//        return this.list(new Query(criteria));
//    }

    public Pagination<ThreeRate> findByTimeRangeAndTeachingClassCodePaged(Integer pageSize, Integer pageNum, Long startTime, Long endTime, String teachingClassCode) throws Exception {
        if (pageSize == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少每页数量.");
        }
        if (pageNum == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少当前页号.");
        }
        if (startTime == null || endTime == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少时间范围.");
        }
        if (teachingClassCode == null) {
            throw new TyrfingServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "缺少教学班代码.");
        }

        // 构造查询条件
        Query query = new Query();
        query.addCriteria(Criteria.where("imagShotTime").gte(startTime).lte(endTime)
                .and("teachingClassCode").is(teachingClassCode));

        // 设置分页
        Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
        query.with(pageable);

        // 查询 MongoDB
        List<ThreeRate> threeRates = mongoTemplate.find(query, ThreeRate.class);
        // 查询总记录数
        long totalCount = mongoTemplate.count(query.skip(-1).limit(-1), ThreeRate.class);

        // 创建分页对象并设置数据
        Pagination<ThreeRate> pagination = new Pagination<>(pageSize, pageNum);
        pagination.setData(threeRates);
        pagination.setTotal((int) totalCount);

        return pagination;
    }


    // 查找最新的ThreeRate记录，根据teachingClassCode或classRoomCode，imagShotTime最新的那个记录
    public ThreeRate findLatestByTeachingClassCodeOrClassRoomCode(String teachingClassCode, String classRoomCode) throws TyrfingMongoException {
        ThreeRate latestRecord = null;

        // 当都为空时，抛出异常
        if ((teachingClassCode == null || teachingClassCode.isEmpty()) && (classRoomCode == null || classRoomCode.isEmpty())) {
            log.error("Both teachingClassCode and classRoomCode cannot be null or empty.");
            throw new TyrfingMongoException("Both teachingClassCode and classRoomCode cannot be null or empty.");
        }

        // 查询 teachingClassCode 下的最新记录
        if (teachingClassCode != null && !teachingClassCode.isEmpty()) {
            Query teachingClassQuery = new Query(Criteria.where("teachingClassCode").is(teachingClassCode))
                    .with(Sort.by(Sort.Direction.DESC, "imagShotTime")).limit(1);
            ThreeRate teachingClassRecord = this.getTemplate().findOne(teachingClassQuery, getClazz());

            if (teachingClassRecord != null) {
                latestRecord = teachingClassRecord; // 先赋值最新记录
            }
        }

        // 查询 classRoomCode 下的最新记录
        if (classRoomCode != null && !classRoomCode.isEmpty()) {
            Query classRoomQuery = new Query(Criteria.where("classRoomCode").is(classRoomCode))
                    .with(Sort.by(Sort.Direction.DESC, "imagShotTime")).limit(1);
            ThreeRate classRoomRecord = this.getTemplate().findOne(classRoomQuery, getClazz());

            // 如果 classRoomRecord 比 teachingClassRecord 更新，则替换
            if (classRoomRecord != null) {
                if (latestRecord == null || classRoomRecord.getImagShotTime() > latestRecord.getImagShotTime()) {
                    latestRecord = classRoomRecord;
                }
            }
        }

        return latestRecord;
    }

    @Override
    public ThreeRate save(ThreeRate threeRate) throws TyrfingServiceException {
        try {
            if (threeRate.getImagShotTime() == null) {
                log.error("imagShptTime can't be null,Failed to save ThreeRate record");
                throw TyrfingServiceException.someThingWentWrong();
            }
            return super.getTemplate().save(threeRate);
        } catch (TyrfingMongoException e) {
            log.error("Failed to save ThreeRate record", e);
            throw TyrfingServiceException.someThingWentWrong();
        }
    }

    @Override
    public ThreeRate remove(String id) throws TyrfingServiceException {
        throw new UnsupportedOperationException("Removing by id is not supported in this mapper.");
    }

    @Override
    public ThreeRate findById(String id) {
        throw new UnsupportedOperationException("Finding by id is not supported in this mapper.");
    }
}
